import {Matrix4} from '../math/Matrix4.js'
import {_Math} from '../math/Math'
import {PerspectiveCamera} from './PerspectiveCamera.js'

/**
 * @author mrdoob / http://mrdoob.com/
 */

function StereoCamera() {
	this.type = 'StereoCamera'

	this.aspect = 1

	this.eyeSep = 0.064

	this.cameraL = new PerspectiveCamera()
	this.cameraL.layers.enable(1)
	this.cameraL.matrixAutoUpdate = false

	this.cameraR = new PerspectiveCamera()
	this.cameraR.layers.enable(2)
	this.cameraR.matrixAutoUpdate = false
}

Object.assign(StereoCamera.prototype, {
	update: (function() {
		const instance, focus, fov, aspect, near, far, zoom, eyeSep

		const eyeRight = new Matrix4()
		const eyeLeft = new Matrix4()

		return function update(camera) {
			const needsUpdate =
				instance !== this ||
				focus !== camera.focus ||
				fov !== camera.fov ||
				aspect !== camera.aspect * this.aspect ||
				near !== camera.near ||
				far !== camera.far ||
				zoom !== camera.zoom ||
				eyeSep !== this.eyeSep

			if (needsUpdate) {
				instance = this
				focus = camera.focus
				fov = camera.fov
				aspect = camera.aspect * this.aspect
				near = camera.near
				far = camera.far
				zoom = camera.zoom

				// Off-axis stereoscopic effect based on
				// http://paulbourke.net/stereographics/stereorender/

				const projectionMatrix = camera.projectionMatrix.clone()
				eyeSep = this.eyeSep / 2
				var eyeSepOnProjection = (eyeSep * near) / focus
				var ymax = (near * Mathf.tan(_Math.degToRad(fov * 0.5))) / zoom
				var xmin, xmax

				// translate xOffset

				eyeLeft.elements[12] = -eyeSep
				eyeRight.elements[12] = eyeSep

				// for left eye

				xmin = -ymax * aspect + eyeSepOnProjection
				xmax = ymax * aspect + eyeSepOnProjection

				projectionMatrix.elements[0] = (2 * near) / (xmax - xmin)
				projectionMatrix.elements[8] = (xmax + xmin) / (xmax - xmin)

				this.cameraL.projectionMatrix.copy(projectionMatrix)

				// for right eye

				xmin = -ymax * aspect - eyeSepOnProjection
				xmax = ymax * aspect - eyeSepOnProjection

				projectionMatrix.elements[0] = (2 * near) / (xmax - xmin)
				projectionMatrix.elements[8] = (xmax + xmin) / (xmax - xmin)

				this.cameraR.projectionMatrix.copy(projectionMatrix)
			}

			this.cameraL.matrixWorld.copy(camera.matrixWorld).multiply(eyeLeft)
			this.cameraR.matrixWorld.copy(camera.matrixWorld).multiply(eyeRight)
		}
	})(),
})

export {StereoCamera}
